from __future__ import division
import math
from pygame import Rect as pygrect

#import numpy

class Rect(pygrect):
	def collidecircle(self, circle):
		return circle.colliderect(self)
	
	def multiply(self, factor):
		x, y = self.topleft
		
		return Rect(math.floor(x * factor), math.floor(y * factor), 
			math.floor(self.width * factor), math.floor(self.height * factor))
	
	def divide(self, dividend):
		x, y = self.topleft
		
		return Rect(x // dividend, y // dividend, self.width // dividend, self.height // dividend)
	
	def circle(self):
		return Circle(self.center, max(self.width, self.height) // 2)
	
	def __iter__(self):
		x, y = self.topleft
		
		return iter((x, y, self.width, self.height))

class Circle(object):
	def __init__(self, position, radius):
		self.position = position
		self.radius = radius
		
		self.x, self.y = position
	
	def move_ip(self, position):
		self.position = position
		self.x, self.y = position
	
	def collidecircle(self, circle):
		return (self.x - circle.x)**2 + (self.y - circle.y)**2 < (self.radius + circle.radius)**2
	
	def colliderect(self, rect):
		return self.rect().colliderect(rect)
	
	def rect(self):
		return Rect(self.x - self.radius, self.y - self.radius, self.radius, self.radius)
		
	def __iter__(self):
		return iter((self.position, self.radius))
		
class CollisionLayer(object):
	"""A collision layer is a grid of cells that contains a list of all
	objects that are touching that cell and so could be collided with by
	something else in that cell."""
	
	def __init__(self, size):
		"""Create the layer and its grid and it to the list of layers."""
		self.size = size
		self.rect = Rect(0, 0, self.size[0], self.size[1])
		self.rect32 = self.rect.multiply(32)
		
		width, height = self.size
		self.objects = [[set() for x in xrange(width + 1)] for y in xrange(height + 1)]
		#self.array = numpy.array(self.objects)
	
	def add(self, object, rect):
		"""Add an object to the layer in all cells that rect touches."""
		rect = rect.divide(32)
		rect = rect.clip(self.rect)
		
		if self.rect.collidepoint(rect.topleft):
			start_x, start_y = rect.topleft
			end_x, end_y = rect.bottomright
			
			for grid_x in xrange(start_x, end_x + 1):
				for grid_y in xrange(start_y, end_y + 1):
					self.objects[grid_y][grid_x].add(object)
			
			"""for cell in self.array[start_x:end_x + 1, start_y:end_y + 1].flat:
				cell.add(object)"""
	
	def clear(self):
		"""Clear all objects from the layer."""
		for row in self.objects:
			for cell in row:
				cell.clear()
		
		"""for cell in self.array.flat:
			cell.clear()"""

	def objects_within_rect(self, rect):
		"""Return all objects within the given rect."""
		objects = set()
		
		if not self.rect32.colliderect(rect):
			return objects
		
		rect = rect.divide(32)
		rect = rect.clip(self.rect)
		
		#rect = rect.clip(self.rect32)
		#rect = rect.multiply(1 / 32)
		
		start_x, start_y = rect.topleft
		end_x, end_y = rect.bottomright
		
		for grid_x in xrange(start_x, end_x + 1):
			for grid_y in xrange(start_y, end_y + 1):
				objects.update(self.objects[grid_y][grid_x])
		
		"""for cell in self.array[start_x:end_x + 1, start_y:end_y + 1].flat:
			objects.update(cell)"""
			
		return objects
